class: center, middle, inverse, title-slide #
## Introduction Avancée ### Mickaël Canouil,
Ph.D.
(
mickael.canouil.fr
) ### Dernière mise à jour : 07-10-2021 --- class: part-slide # Introduction à <i class="fab fa-r-project"></i> --- # Installation de <i class="fab fa-r-project"></i> Site internet officiel : https://www.r-project.org/ > R is a language and environment for statistical computing and graphics. > It is a GNU project which is similar to the S language and environment which was developed at Bell Laboratories (formerly AT&T, now Lucent Technologies) by John Chambers and colleagues. > R can be considered as a different implementation of S. > There are some important differences, but much code written for S runs unaltered under R. > > R provides a wide variety of statistical (linear and nonlinear modelling, classical statistical tests, time-series analysis, classification, clustering, ...) and graphical techniques, and is highly extensible. > The S language is often the vehicle of choice for research in statistical methodology, and R provides an Open Source route to participation in that activity. > > One of R’s strengths is the ease with which well-designed publication-quality plots can be produced, including mathematical symbols and formulae where needed. > Great care has been taken over the defaults for the minor design choices in graphics, but the user retains full control. .center.font200[⇒ [**Download R**](https://cloud.r-project.org/)] --- # Sauvegarder le code ... Pas l'environnement ! .pull-left.font150[ Les scripts : * "*standards*" dans un fichier `.R` * "*Rmarkdown*" dans un fichier `.Rmd` ] .pull-right.font150[ Les "données" : * un objet dans un `.rds` * une liste d'objet dans un `.Rdata` ] --- # Utiliser un IDE ("Integrated Development Environment") .font150[ * RStudio : https://www.rstudio.com/products/rstudio/download/#download * Emacs + ESS : https://ess.r-project.org * vim + Nvim-R : https://medium.com/free-code-camp/turning-vim-into-an-r-ide-cd9602e8c217 * Visual Studio Code + vscode-R : https://github.com/REditorSupport/vscode-R ] --- # Faire *table rase* à chaque démarrage ! .font150[ Lorsque vous quittez <i class="fab fa-r-project"></i> : * Ne pas enregistrer votre espace de travail (*workspace**) ! Lorsque vous démarrez <i class="fab fa-r-project"></i> : * Ne pas charger l'espace de travail sauvegardé précédemment ! ] .footnote.font150[ * Le *workspace* est automatiquement sauvegardé/chargé via un fichier nommé `.Rdata` (là où s'exécute <i class="fab fa-r-project"></i>). ] --- # Faire *table rase* ! Dans Windows .center[<img src = "data:image/png;base64,#content/media/rwindows.png" />] --- # Faire *table rase* ! Dans RStudio (*Tools > Global options*) .center[<img src = "data:image/png;base64,#content/media/rstudio.png" />] # Faire *table rase* ! .pull-left.font150[ + Dans un Terminal ```bash R --no-save --no-restore-data ``` ] .pull-right.font150[ + `.bash_profile` / `.bashrc` / ... ```bash alias R='R --no-save --no-restore-data' ``` ] --- # Comment Réinitialiser <i class="fab fa-r-project"></i> ? Avec `rm(list = ls())` ? .font150[ > If the first line of your R script is > > `rm(list = ls())` > > I will come into your office and SET YOUR COMPUTER ON FIRE 🔥. > > --- Jenny Bryan ] --- # Que ne fait pas `rm(list = ls())` ? .font150[ * Réinitialiser la session <i class="fab fa-r-project"></i> en cours * Réinitialiser les `options()` → `options(stringsAsFactors = FALSE)`* * Réinitialiser le répertoire de travail `getwd()` → `setwd()` * Réinitialiser les extensions <i class="fab fa-r-project"></i> attachées ] .footnote.font150[ * Valeur par défaut <i class="fab fa-r-project"></i> v4.0.0 ([Kurt Hornik: stringsAsFactors](https://developer.r-project.org/Blog/public/2020/02/16/stringsasfactors/)). ] --- # Mais alors que fait `rm(list = ls())` ? ```r help(rm) ``` .center[<img src = "data:image/png;base64,#content/media/rm-doc.png" />] --- # Réinitialiser <i class="fab fa-r-project"></i> .font150[ * Dans une console <i class="fab fa-r-project"></i> * Via le raccourci `Ctrl+D` * Via la fonction `q()` dans une console <i class="fab fa-r-project"></i> ] --- # Réinitialiser <i class="fab fa-r-project"></i> .pull-left.font150[ * Dans RStudio : * Via le raccourci `Ctrl+Shift+F10` * Via le menu ] .pull-right[ .center[<img src = "data:image/png;base64,#content/media/restartr.png" />] ] --- # Désactiver les fichiers de démarrage .font150[ * `--vanilla` - pour désactiver le chargement de **tous les fichiers** de démarrage * `--no-init-file` - pour désactiver le chargement du fichier `.Rprofile` * `--no-environ` - pour désactiver le chargement du fichier `.Renviron` ] --- # `setwd(...)` en première ligne d'un script ... .font150[ > If the first line of your R script is > > `setwd("C:\Users\jenny\path\that\only\I\have")` > > I will come into your office and SET YOUR COMPUTER ON FIRE 🔥. > > --- Jenny Bryan ] --- # Faisons le Point sur `setwd()` ! .pull-left.code150[ ```r library(ggplot2) setwd("/path/to/a/directory/on/my/laptop/data") df <- read.delim("data.csv") p <- ggplot(df, aes(x, y)) + geom_point() ggsave("../figs/scatterplot.png") ``` ] .pull-right.code150[ ```r library(ggplot2) setwd("/path/to/a/directory/on/my/laptop/data") df <- read.delim("data.csv") p <- ggplot(df, aes(x, y)) + geom_point() setwd("/path/to/a/directory/on/my/laptop/figs") ggsave("scatterplot.png") ``` ] --- # L'extension <i class = "fab fa-r-project"></i> `here` .pull-left[ .center[<img src = "data:image/png;base64,#content/media/here_ahorst.png" />] ] .pull-right.code60[ ```r here::here() ``` ``` #> [1] "D:/Profils/mcanouil/PROJECTS/mc-radvanced" ``` ```r here::i_am("radvanced.Rmd") ``` ``` #> here() starts at D:/Profils/mcanouil/PROJECTS/mc-radvanced ``` ```r here::i_am("content/part-0.Rmd") ``` ``` #> Error: Could not find associated project in working directory or any parent directory. #> - Path in project: content/part-0.Rmd #> - Current working directory: D:/Profils/mcanouil/PROJECTS/mc-radvanced/content #> Please open the project associated with this file and try again. ``` ```r fs::dir_tree(here::here(), recurse = FALSE) ``` ``` #> D:/Profils/mcanouil/PROJECTS/mc-radvanced #> +-- assets #> +-- content #> +-- docs #> +-- LICENSE.md #> +-- radvanced.Rmd #> +-- README.md #> +-- README.Rmd #> \-- thumbs ``` ] --- # Utiliser un Mode "Projet" via un IDE .font150[ * Démarrer un projet A : 1. Démarre R. 2. Défini le répetoire de travail de R comme la racine du projet A. * Passer d'un projet A à un project B : 1. Redémarre R. 2. Défini le répetoire de travail de R comme la racine du projet B. ] --- # Utiliser un Mode "Projet" .font150[ * [__"What They Forgot to Teach You About R"__](https://rstats.wtf/project-oriented-workflow.html) --- Jenny Bryan & Jim Hester * [__"Project-oriented Workflow"__](https://www.tidyverse.org/articles/2017/12/workflow-vs-script/) --- Jenny Bryan ] --- # Lectures Utiles .font150[ * [__"Code Smells and Feels"__](https://www.youtube.com/watch?v=7oyiPBjLAWY) --- Jenny Bryan * [__"Advanced R"__](https://adv-r.hadley.nz/) --- Hadley Wickham * [__"Project-oriented Workflow"__](https://www.tidyverse.org/articles/2017/12/workflow-vs-script/) --- Jenny Bryan * [__"R for Data Science"__](https://r4ds.had.co.nz/) --- Garrett Grolemund & Hadley Wickham * [__"What They Forgot to Teach You About R"__](https://rstats.wtf/) --- Jenny Bryan & Jim Hester ] --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Noms et Valeurs --- # Affectation ```r x <- c(1, 2, 3) ``` "Crée un objet nommé 'x', contenant les valeurs 1, 2 et 3" ou plus précisément : * Crée un objet de type vecteur `c(1, 2, 3)`. * Associe cet objet à un nom `x`. --- # Affectation ```r x <- c(1, 2, 3) y <- x ``` ```r lobstr::obj_addr(x) ``` ``` #> [1] "0x1b00c62c988" ``` ```r lobstr::obj_addr(y) ``` ``` #> [1] "0x1b00c62c988" ``` `y` n'est pas une copie de `x`. `x` et `y` sont des références à l'objet de type vecteur `c(1, 2, 3)`. --- # Noms Non-syntaxique <i class="fab fa-r-project"></i> dispose d'un ensemble de règles pour les noms utilisables : * Contient uniquement des lettres (ASCII, mais pas uniquement), des chiffres, `.` et `_`. * Ne peut pas débuter par des chiffres ou `_`. * Ne peut pas être un "nom réservé" (`?Reserved`). --- # Noms Non-syntaxique ```r _abc <- 1 ``` ``` #> Error: <text>:1:1: unexpected input #> 1: _ #> ^ ``` ```r TRUE <- "false" ``` ``` #> Error in TRUE <- "false": invalid (do_set) left-hand side to assignment ``` ```r `_abc` <- 1 ``` ```r `+` <- 1 ``` --- # Exercices 1. Expliquer les relations entre `a`, `b`, `d`, et `e`. ```r a <- 1:10 b <- a b -> e e <- d <- 1:10 ``` 2. Que donne le code suivant pour importer un "fichier" csv ? Quel argument faudrait-il utiliser pour avoir les noms des colonnes tels-qu'ils sont ? ```r read.csv( header = TRUE, text = "1ere_colonne,deuxième_colonne,troisième colonne\n1,2,3" ) ``` 3. Les fonctions `read.*()` utilisent `make.names()` ? Quels sont les règles de conversions utilisées ? --- # Copie sur Modification ("Copy-on-modify") ```r x <- c(1, 2, 3) y <- x y[3] <- 4 x ``` ``` #> [1] 1 2 3 ``` ```r y ``` ``` #> [1] 1 2 4 ``` La modification de `y` n'a pas modifié `x`. <i class="fab fa-r-project"></i> crée une copie de l'objet référencé par `x` en modifiant la troisième valeur. Ce nouvel objet est ensuite référencé par `y`. --- # Déréférencement et "Garbage Collection" ```r x <- 1:3 x <- 2:4 rm(x) # Déréférencement gc() # Force "Garbage Collection" ``` ``` #> used (Mb) gc trigger (Mb) max used (Mb) #> Ncells 1317038 70.4 2387024 127.5 2387024 127.5 #> Vcells 3507343 26.8 10146329 77.5 10146321 77.5 ``` --- # Exercices 1. À quelle ligne, une copie de `a` est effectuée ? ```r a <- c(1, 5, 3, 2) b <- a b[[1]] <- 10 ``` --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Les Vecteurs --- # Les Vecteurs * Booléen : `TRUE` et `FALSE`. * Numérique * Flottant ("double") * Décimal `0.1234`. * Scientifique `1.23e4`. * Hexadécimal `0xcafe`. * Valeurs particulières : `Inf`, `-Inf` et `NaN`. * Entier ("integer") : suffixe `L`, *p.ex.*, `123L`, `1.23e4L` et `0xcafeL`. * Chaîne de caractères : entourées par `"` ou `'`. Les caractères spéciaux sont échappés par `\` (`?Quotes`). --- # Les Vecteurs `c()` ("combine") permet de constituer des vecteurs de longueurs supérieurs à 1. ```r lgl_var <- c(TRUE, FALSE) int_var <- c(1L, 6L, 10L) dbl_var <- c(1, 2.5, 4.5) chr_var <- c("these are", "some strings") ``` Lorsque les éléments de `c()` sont dit atomiques, le résultat est alors de même nature. ```r c(c(1, 2), c(3, 4)) ``` ``` #> [1] 1 2 3 4 ``` --- # Les Vecteurs Le type d'un vecteur peut-être déterminé via `typeof()`. ```r typeof(lgl_var) ``` ``` #> [1] "logical" ``` ```r typeof(int_var) ``` ``` #> [1] "integer" ``` ```r typeof(dbl_var) ``` ``` #> [1] "double" ``` ```r typeof(chr_var) ``` ``` #> [1] "character" ``` --- # Les Vecteurs Et sa longueur via `length()`. ```r length(lgl_var) ``` ``` #> [1] 2 ``` ```r length(int_var) ``` ``` #> [1] 3 ``` ```r length(dbl_var) ``` ``` #> [1] 3 ``` ```r length(chr_var) ``` ``` #> [1] 2 ``` --- # Valeurs Manquantes <i class="fab fa-r-project"></i> symbolise les valeurs manquantes à l'aide de `NA` ("not applicable"). Un calcul impliquant `NA` résultera en un `NA`. ```r NA > 5 ``` ``` #> [1] NA ``` ```r 10 * NA ``` ``` #> [1] NA ``` ```r !NA ``` ``` #> [1] NA ``` --- # Valeurs Manquantes À quelques exceptions. ```r NA ^ 0 ``` ``` #> [1] 1 ``` ```r NA | TRUE ``` ``` #> [1] TRUE ``` ```r NA & FALSE ``` ``` #> [1] FALSE ``` --- # Valeurs Manquantes Détermination des valeurs manquantes d'un vecteur de façon "naïve". ```r x <- c(NA, 5, NA, 10) x == NA ``` ``` #> [1] NA NA NA NA ``` La bonne approche pour éviter les erreurs. ```r is.na(x) ``` ``` #> [1] TRUE FALSE TRUE FALSE ``` --- # Valeurs Manquantes `NA` est la forme "générique", mais il existe un `NA` pour chacun des types : * Booléen : `NA`. * Numérique * Flottant ("double") : `NA_real_`. * Entier ("integer") : `NA_integer_`. * Chaîne de caractères : `NA_character_`. --- # Test et Conversion de Type <i class="fab fa-r-project"></i> dispose de fonctions `is.*()` pour tester le type d'un vecteur, mais sont à utiliser avec précautions. `is.logical()`, `is.integer()`, `is.double()` et `is.character()` effectueront bien le test demandé/attendu. Ce qui ne sera pas nécessairement le cas de `is.vector()`, `is.atomic()` et `is.numeric()`. ```r ?is.numeric ``` > is.numeric is an internal generic primitive function: you can write methods to handle specific classes of objects, see InternalMethods. It is not the same as is.double. Factors are handled by the default method, and there are methods for classes "Date", "POSIXt" and "difftime" (all of which return false). Methods for is.numeric should only return true if the base type of the class is double or integer and values can reasonably be regarded as numeric (e.g., arithmetic on them makes sense, and comparison should be done via the base type). --- # Test et Conversion de Type Un vecteur ne dispose que d'un seul type, c'est-à-dire, tous les éléments doivent avoir le même type. Lorsque les éléments d'un vecteur sont de plusieurs types, une conversion sera appliquée selon la règle de priorité : `character` → `double` → `integer` → `logical`. ```r x <- c("a", 1) typeof(x) ``` ``` #> [1] "character" ``` ```r str(x) ``` ``` #> chr [1:2] "a" "1" ``` --- # Test et Conversion de Type La plupart des fonctions mathématiques réalise cette conversion de type (*p.ex.*, `+`, `log`, etc.). ```r x <- c(FALSE, FALSE, TRUE) as.numeric(x) ``` ``` #> [1] 0 0 1 ``` ```r # Nombre de "TRUE" sum(x) ``` ``` #> [1] 1 ``` ```r # Proportion de "TRUE" mean(x) ``` ``` #> [1] 0.3333333 ``` --- # Test et Conversion de Type Il est possible de convertir explicitement un vecteur avec les fonctions `as.*()` : `as.logical()`, `as.integer()`, `as.double()` et `as.character()`. <i class="fab fa-r-project"></i> avertira via un avertissement d'un problème lors de la conversion. ```r as.integer(c("1", "1.5", "a")) ``` ``` #> Warning: NAs introduced by coercion ``` ``` #> [1] 1 1 NA ``` --- # Exercices 1. Déterminer le type des vecteurs suivants. ```r c(1, FALSE) c("a", 1) c(TRUE, 1L) ``` 2. Déterminer le résultat des comparaisons suivantes. ```r 1 == "1" -1 < FALSE "one" < 2 ``` Pour quelle raison ces résultats ont été obtenu ? 3. Pourquoi le type par défaut de `NA` est booléen ? --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Les Attributs --- # Les Attributs Les attributs sont des meta-données stockées sont la forme de paire nom/valeur. Chaque attribut peut être récupéré et défini individuellement via `attr()`, récupéré en masse via `attributes()` ou encore défini en masse via `structure()`. ```r a <- 1:3 attr(a, "x") <- "abcdef" attr(a, "x") ``` ``` #> [1] "abcdef" ``` ```r attr(a, "y") <- 4:6 str(attributes(a)) ``` ``` #> List of 2 #> $ x: chr "abcdef" #> $ y: int [1:3] 4 5 6 ``` --- # Les Attributs ```r a <- structure( 1:3, x = "abcdef", y = 4:6 ) str(attributes(a)) ``` ``` #> List of 2 #> $ x: chr "abcdef" #> $ y: int [1:3] 4 5 6 ``` --- # Les Attributs Les attributs sont en général éphémères, dans le sens où ils sont perdus dans la plupart des opérations. ```r attributes(a[1]) ``` ``` #> NULL ``` ```r attributes(sum(a)) ``` ``` #> NULL ``` Là encore, il y a principalement deux exceptions : * __noms__ (`names`), un vecteur de chaîne de caractères donnant le nom de chaque élément. * __dimension__ (`dim`), un vecteur de valeurs entières donnant les dimensions (utilisé dans la conversion des vecteurs en matrices ou "arrays"). --- # Les Attributs : Noms Il existe plusieurs façons de nommer les éléments d'un vecteur. * Lors de la création. ```r x <- c(a = 1, b = 2, c = 3) ``` * Avec `names()` pour affecter des un vecteur de chaîne de caractères. ```r x <- 1:3 names(x) <- c("a", "b", "c") ``` * Avec `setNames()`, pour réaliser la même tâche en une seule ligne. ```r x <- setNames(1:3, c("a", "b", "c")) ``` --- # Les Attributs : Dimensions * Les vecteurs sont de dimension `NULL`. ```r dim(1:6) ``` ``` #> NULL ``` * Les matrices sont de dimension `2`. ```r x <- matrix(1:6, nrow = 2, ncol = 3) dim(x) ``` ``` #> [1] 2 3 ``` * Les "arrays" sont de dimension `n`. ```r x <- array(1:12, dim = c(2, 3, 2)) dim(x) ``` ``` #> [1] 2 3 2 ``` --- # Les Attributs : Dimensions Il est possible de modifier directement les dimensions d'un vecteur pour en modifier la "forme". ```r x <- 1:6 dim(x) <- c(3, 2) x ``` ``` #> [,1] [,2] #> [1,] 1 4 #> [2,] 2 5 #> [3,] 3 6 ``` --- # Les Attributs : Dimensions
Vector
Matrix
Array
names()
rownames(), colnames()
dimnames()
length()
nrow(), ncol()
dim()
c()
rbind(), cbind()
abind::abind()
---
t()
aperm()
is.null(dim(x))
is.matrix()
is.array()
--- # Les Attributs : Dimensions `str()` est le meilleur moyen d'identifier la "nature" d'un objet. ```r str(1:3) # 1d vector ``` ``` #> int [1:3] 1 2 3 ``` ```r str(matrix(1:3, ncol = 1)) # column vector ``` ``` #> int [1:3, 1] 1 2 3 ``` ```r str(matrix(1:3, nrow = 1)) # row vector ``` ``` #> int [1, 1:3] 1 2 3 ``` ```r str(array(1:3, 3)) # "array" vector ``` ``` #> int [1:3(1d)] 1 2 3 ``` --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Les Vecteurs (Objets) S3 --- # Les Vecteurs (Objets) S3 `class` est un autre attribut important dans <i class="fab fa-r-project"></i>, il est le fondement du système objet S3. Un objet possédant l'attribut `class` devient un __objet S3__ qui réagira différemment d'un simple objet au regard d'une fonction dite "générique". Les principaux vecteurs S3 : * `factor`, permettant de définir des niveaux pour un vecteur. * `Date`, la date dans un format défini au jour près. * `POSIXct`, la date dans un format défini à la seconde près. --- # Les Vecteurs (Objets) S3 : Les Facteurs Un facteur est un vecteur ne pouvant contenir que des valeurs prédéfinies. Ce type de vecteur est utilisé pour stocker des données catégorielles / discrètes en se basant sur un vecteur d'entier. ```r x <- factor(c("a", "b", "b", "a")) x ``` ``` #> [1] a b b a #> Levels: a b ``` ```r typeof(x) ``` ``` #> [1] "integer" ``` --- # Les Vecteurs (Objets) S3 : Les Facteurs Un facteur est un vecteur ne pouvant contenir que des valeurs prédéfinies. Ce type de vecteur est utilisé pour stocker des données catégorielles / discrètes en se basant sur un vecteur d'entier. ```r attributes(x) ``` ``` #> $levels #> [1] "a" "b" #> #> $class #> [1] "factor" ``` ```r str(x) ``` ``` #> Factor w/ 2 levels "a","b": 1 2 2 1 ``` --- # Les Vecteurs (Objets) S3 : Les Facteurs Les niveaux d'un facteur peuvent être connus, mais pas nécessairement observés dans les données. ```r sex_char <- c("m", "m", "m") sex_factor <- factor(sex_char, levels = c("m", "f")) ``` Ainsi, il est possible de compter les occurrences de l'ensemble des niveaux. ```r table(sex_char) ``` ``` #> sex_char #> m #> 3 ``` ```r table(sex_factor) ``` ``` #> sex_factor #> m f #> 3 0 ``` --- # Les Vecteurs (Objets) S3 : Les Facteurs Les facteurs peuvent également être ordonnées et se comportent comme des facteurs "classiques". ```r ordered(c("b", "b", "a", "c"), levels = c("c", "b", "a")) ``` ``` #> [1] b b a c #> Levels: c < b < a ``` ```r factor( c("b", "b", "a", "c"), levels = c("c", "b", "a"), ordered = TRUE) ``` ``` #> [1] b b a c #> Levels: c < b < a ``` __Note :__ Les fonctions `read.*()` et `data.frame()` convertissent automatique les vecteurs de chaîne de caractères en facteurs. Il est recommandé de désactiver ce comportant `options(stringsAsFactors = FALSE)` (Par défaut avec `R > 4.0`). --- # Exercices 1. Quelle sorte d'objet renvoi `table()` ? Quel est son type ? Quels sont ses attributs ? 2. Qu'arrive-t-il à un facteur lorsque les niveaux sont modifiés ? ```r f1 <- factor(letters) levels(f1) <- rev(levels(f1)) ``` 3. Que fait le code suivant ? De quelle façon `f2` et `f3` différent-ils de `f1` ? ```r f2 <- rev(factor(letters)) f3 <- factor(letters, levels = rev(letters)) ``` --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Les Listes --- # Les Listes À la différence des vecteurs, les éléments d'une liste peuvent être de n'importe quel type, il n'est plus question de "cohérence de type". ```r l1 <- list( 1:3, "a", c(TRUE, FALSE, TRUE), c(2.3, 5.9) ) typeof(l1) ``` ``` #> [1] "list" ``` --- # Les Listes À la différence des vecteurs, les éléments d'une liste peuvent être de n'importe quel type, il n'est plus question de "cohérence de type". ```r str(l1) ``` ``` #> List of 4 #> $ : int [1:3] 1 2 3 #> $ : chr "a" #> $ : logi [1:3] TRUE FALSE TRUE #> $ : num [1:2] 2.3 5.9 ``` --- # Les Listes Chaque élément d'une liste, n'est en réalité qu'une référence à l'objet. ```r lobstr::obj_size(mtcars) ``` ``` #> 3,016 B ``` ```r l2 <- list(mtcars, mtcars, mtcars, mtcars) lobstr::obj_size(l2) ``` ``` #> 3,096 B ``` --- # Les Listes La levée de la contrainte de "cohérence de type" fait des listes un type particulièrement flexible et de ce fait ne permet pas d'avoir une représentation générique efficace systématiquement, comme c'est le cas pour les vecteurs. ```r l3 <- list(list(list(1))) str(l3) ``` ``` #> List of 1 #> $ :List of 1 #> ..$ :List of 1 #> .. ..$ : num 1 ``` --- # Les Listes `c()` permet de combiner des éléments dans le cas des listes. ```r l4 <- list(list(1, 2), c(3, 4)) str(l4) ``` ``` #> List of 2 #> $ :List of 2 #> ..$ : num 1 #> ..$ : num 2 #> $ : num [1:2] 3 4 ``` ```r l5 <- c(list(1, 2), c(3, 4)) str(l5) ``` ``` #> List of 4 #> $ : num 1 #> $ : num 2 #> $ : num 3 #> $ : num 4 ``` --- # Test et Conversion de Type Le `typeof()` d'une liste est `list`. `is.list()` permet de tester si l'objet est une liste quand `as.list()` permet la conversion en liste. ```r list(1:3) ``` ``` #> [[1]] #> [1] 1 2 3 ``` ```r as.list(1:3) ``` ``` #> [[1]] #> [1] 1 #> #> [[2]] #> [1] 2 #> #> [[3]] #> [1] 3 ``` --- # Matrices et Arrays L'attribut `dim` permettait de passer d'un vecteur à une matrice ou à un array. Dans le cas des listes, il permet de passer à des "matrice-liste" et "array-liste". ```r l <- list(1:3, "a", TRUE, 1.0) dim(l) <- c(2, 2) l ``` ``` #> [,1] [,2] #> [1,] integer,3 TRUE #> [2,] "a" 1 ``` ```r l[[1, 1]] ``` ``` #> [1] 1 2 3 ``` --- # Exercices 1. Lister les points de divergences entre un vecteur et une liste. 2. Pourquoi `as.vector()` ne fonctionne pas pour convertir une liste en vecteur ? Pourquoi l'usage de `unlist()` est nécessaire ? --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Les `data.frame` --- # `data.frame` L'une des classes S3 importante dans <i class="fab fa-r-project"></i> est la classe `data.frame` (`tibble` dans le "tidyverse"), qui repose entièrement sur les listes. Qu'est-ce qu'un `data.frame` ? Un `data.frame` est une liste nommée, de vecteur de même dimension (longueur) avec des attributs `names` (noms des colonnes) et `row.names`. ```r df1 <- data.frame(x = 1:3, y = letters[1:3]) typeof(df1) ``` ``` #> [1] "list" ``` --- # `data.frame` L'une des classes S3 importante dans <i class="fab fa-r-project"></i> est la classe `data.frame` (`tibble` dans le "tidyverse"), qui repose entièrement sur les listes. Qu'est-ce qu'un `data.frame` ? Un `data.frame` est une liste nommée, de vecteur de même longueur avec des attributs `names` (noms des colonnes) et `row.names`. ```r attributes(df1) ``` ``` #> $names #> [1] "x" "y" #> #> $class #> [1] "data.frame" #> #> $row.names #> [1] 1 2 3 ``` --- # `data.frame` Un `data.frame` a donc une structure rectangulaire et dispose de noms pour les lignes et les colonnes. * `rownames()` pour obtenir le noms des lignes. * `colnames()` (ou `names()`) pour obtenir le noms des colonnes. * `nrow()` pour obtenir le nombre de lignes. * `ncol()` (ou `length()`) pour obtenir le nombre de colonnes. --- # `data.frame` La création d'un `data.frame` se fait via `data.frame()`. ```r df <- data.frame( x = 1:3, y = c("a", "b", "c") ) str(df) ``` ``` #> 'data.frame': 3 obs. of 2 variables: #> $ x: int 1 2 3 #> $ y: chr "a" "b" "c" ``` --- # `data.frame` La création d'un `data.frame` se fait via `data.frame()`. ```r df <- data.frame( x = 1:3, y = c("a", "b", "c"), stringsAsFactors = TRUE # Par défaut dans R < 4.0 ) str(df) ``` ``` #> 'data.frame': 3 obs. of 2 variables: #> $ x: int 1 2 3 #> $ y: Factor w/ 3 levels "a","b","c": 1 2 3 ``` --- # `data.frame` La création d'un `data.frame` se fait via `data.frame()`. ```r df <- data.frame( x = 1:3, y = c("a", "b", "c"), stringsAsFactors = FALSE # Par défaut dans R > 4.0 ) str(df) ``` ``` #> 'data.frame': 3 obs. of 2 variables: #> $ x: int 1 2 3 #> $ y: chr "a" "b" "c" ``` --- # `data.frame` Par défaut, un `data.frame` requiert des noms de colonnes syntaxiquement correct. ```r names(data.frame(`1` = 1)) ``` ``` #> [1] "X1" ``` ```r names(data.frame(`1` = 1, check.names = FALSE)) ``` ``` #> [1] "1" ``` --- # `data.frame` Un `data.frame` requiert que ces éléments soit de même longueur, quand cela n'est pas respecté et lorsque c'est possible, les valeurs des vecteurs les plus courts sont recyclés. ```r data.frame(x = 1:4, y = 1:2) ``` ``` #> x y #> 1 1 1 #> 2 2 2 #> 3 3 1 #> 4 4 2 ``` ```r data.frame(x = 1:4, y = 1:3) ``` ``` #> Error in data.frame(x = 1:4, y = 1:3): les arguments impliquent des nombres de lignes différents : 4, 3 ``` --- # `data.frame` Les `data.frame` ayant des noms de lignes, il est possible de les définir de plusieurs façons. ```r df3 <- data.frame( age = c(35, 27, 18), hair = c("blond", "brown", "black"), row.names = c("Bob", "Susan", "Sam") ) df3 ``` ``` #> age hair #> Bob 35 blond #> Susan 27 brown #> Sam 18 black ``` --- # `data.frame` Les `data.frame` ayant des noms de lignes, il est possible de les définir de plusieurs façons. ```r df3 <- data.frame( age = c(35, 27, 18), hair = c("blond", "brown", "black") ) rownames(df3) <- c("Bob", "Susan", "Sam") df3 ``` ``` #> age hair #> Bob 35 blond #> Susan 27 brown #> Sam 18 black ``` --- # `data.frame` L'usage des noms de lignes n'est pas recommandé. * Le nom des lignes est une donnée, pourquoi la stocker différemment ? * Le nom des lignes doit obligatoirement être une chaîne de caractères. * Chaque nom de ligne doit-être unique. <i class="fab fa-r-project"></i> s'assurera que ce soit le cas ! ```r df3[c(1, 1, 1), ] ``` ``` #> age hair #> Bob 35 blond #> Bob.1 35 blond #> Bob.2 35 blond ``` --- # Test et Conversion de Type `is.data.frame()` permet de tester si l'objet est un `data.frame()` quand `as.data.frame()` permet la conversion. ```r is.data.frame(df1) ``` ``` #> [1] TRUE ``` --- # Exercises 1. Est-il possible d'avoir un `data.frame` avec zéro lignes ? Et zéro colonnes ? 2. Que se passe-t-il lorsque des noms lignes avec duplicatas sont définis via `rownames()` ? 3. Que donne `t(df)` ou `t(t(df))` ? Avec, `df` un objet de classe `data.frame`. 4. Que fait `as.matrix()` sur un `data.frame` dont les colonnes sont de type différents ? --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>`NULL` --- # `NULL` `NULL` un objet particulier. ```r typeof(NULL) ``` ``` #> [1] "NULL" ``` ```r length(NULL) ``` ``` #> [1] 0 ``` ```r x <- NULL attr(x, "y") <- 1 ``` ``` #> Error in attr(x, "y") <- 1: attempt to set an attribute on NULL ``` --- # `NULL` Il est possible de tester le caractère `NULL` d'un objet. ```r is.null(NULL) ``` ``` #> [1] TRUE ``` `NULL` sert à définir : * un vecteur vide (*p.ex.*, `c()`). * un vecteur absent (*p.ex.*, argument non défini d'une fonction). --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Sélection --- # Sélection Dans un Vecteur * Entier positif. ```r x <- c(2.1, 4.2, 3.3, 5.4) ``` ```r x[c(3, 1)] ``` ``` #> [1] 3.3 2.1 ``` ```r x[c(1, 1)] ``` ``` #> [1] 2.1 2.1 ``` ```r x[c(2.1, 2.9)] # Troncature ``` ``` #> [1] 4.2 4.2 ``` --- # Sélection Dans un Vecteur * Entier négatif. ```r x <- c(2.1, 4.2, 3.3, 5.4) ``` ```r x[-c(3, 1)] ``` ``` #> [1] 4.2 5.4 ``` ```r x[c(-1, 2)] # Pas de mélange ``` ``` #> Error in x[c(-1, 2)]: only 0's may be mixed with negative subscripts ``` --- # Sélection Dans un Vecteur * Booléen. ```r x <- c(2.1, 4.2, 3.3, 5.4) ``` ```r x[c(TRUE, TRUE, FALSE, FALSE)] ``` ``` #> [1] 2.1 4.2 ``` ```r x[x > 3] ``` ``` #> [1] 4.2 3.3 5.4 ``` --- # Sélection Dans un Vecteur * Recyclage des valeurs. ```r x <- c(2.1, 4.2, 3.3, 5.4) ``` ```r x[c(TRUE, FALSE)] # Recyclage ``` ``` #> [1] 2.1 3.3 ``` ```r x[c(TRUE, FALSE, TRUE, FALSE)] ``` ``` #> [1] 2.1 3.3 ``` --- # Sélection Dans un Vecteur * Valeur manquante. ```r x <- c(2.1, 4.2, 3.3, 5.4) ``` ```r x[c(TRUE, TRUE, NA, FALSE)] ``` ``` #> [1] 2.1 4.2 NA ``` --- # Sélection Dans un Vecteur * "Rien". ```r x <- c(2.1, 4.2, 3.3, 5.4) ``` ```r x[] ``` ``` #> [1] 2.1 4.2 3.3 5.4 ``` --- # Sélection Dans un Vecteur * Zéro. ```r x <- c(2.1, 4.2, 3.3, 5.4) ``` ```r x[0] ``` ``` #> numeric(0) ``` --- # Sélection Dans un Vecteur * Avec des "noms". ```r x <- c(2.1, 4.2, 3.3, 5.4) names(x) <- letters[1:4] ``` ```r x[c("d", "c", "a")] ``` ``` #> d c a #> 5.4 3.3 2.1 ``` ```r x[c("a", "a", "a")] ``` ``` #> a a a #> 2.1 2.1 2.1 ``` --- # Sélection Dans un Vecteur * Avec des "noms", une correspondance parfaite est requise. ```r z <- c(abc = 1, def = 2) ``` ```r z[c("a", "d")] # Correspondance parfaite ``` ``` #> <NA> <NA> #> NA NA ``` ```r z[c("abc", "def")] ``` ``` #> abc def #> 1 2 ``` --- # Sélection Dans une Liste La sélection s'opère de la même façon que sur un vecteur. * `[`, renvoi une liste. * `[[` et `$`, renvoient un élément d'une liste. --- # Sélection Dans une Liste La sélection s'opère de la même façon que sur un vecteur. * `[`, renvoi une liste. ```r x <- list(2.1, 4.2, 3.3, 5.4) x[c(1, 3)] ``` ``` #> [[1]] #> [1] 2.1 #> #> [[2]] #> [1] 3.3 ``` ```r x[[2]] ``` ``` #> [1] 4.2 ``` --- # Sélection Dans une Liste La sélection s'opère de la même façon que sur un vecteur. * `[[` et `$`, renvoient un élément d'une liste. ```r x <- list(2.1, 4.2, 3.3, 5.4) names(x) <- letters[1:4] x$a ``` ``` #> [1] 2.1 ``` ```r x[["b"]] ``` ``` #> [1] 4.2 ``` --- # Sélection Dans une Matrice ou Array La sélection peut s'effectuer avec un vecteur, plusieurs vecteurs ou une matrice. ```r a <- matrix(1:9, nrow = 3) colnames(a) <- c("A", "B", "C") a[1:2, ] ``` ``` #> A B C #> [1,] 1 4 7 #> [2,] 2 5 8 ``` ```r a[c(TRUE, FALSE, TRUE), c("B", "A")] ``` ``` #> B A #> [1,] 4 1 #> [2,] 6 3 ``` --- # Sélection Dans une Matrice ou Array Comme les matrices ou arrays ne sont que des vecteurs avec un attribut `dim`, la sélection peut se faire directement avec un seul vecteur de position. ```r vals <- outer(1:5, 1:5, FUN = "paste", sep = ",") vals ``` ``` #> [,1] [,2] [,3] [,4] [,5] #> [1,] "1,1" "1,2" "1,3" "1,4" "1,5" #> [2,] "2,1" "2,2" "2,3" "2,4" "2,5" #> [3,] "3,1" "3,2" "3,3" "3,4" "3,5" #> [4,] "4,1" "4,2" "4,3" "4,4" "4,5" #> [5,] "5,1" "5,2" "5,3" "5,4" "5,5" ``` ```r vals[c(4, 15)] ``` ``` #> [1] "4,1" "5,3" ``` --- # Sélection Dans une Matrice ou Array Il est également possible d'effectuer la sélection à partir d'une matrice donnant la position des dans chacune des dimensions de la matrice ou array que l'on souhaite manipuler. ```r vals <- outer(1:5, 1:5, FUN = "paste", sep = ",") select <- matrix(ncol = 2, byrow = TRUE, c( 1, 1, 3, 1, 2, 4 )) vals[select] ``` ``` #> [1] "1,1" "3,1" "2,4" ``` --- # Sélection Dans un `data.frame` Les `data.frame` se comportent comme des listes et comme des matrices. ```r df <- data.frame(x = 1:3, y = 3:1, z = letters[1:3]) df[df$x == 2, ] ``` ``` #> x y z #> 2 2 2 b ``` ```r df[c(1, 3), ] ``` ``` #> x y z #> 1 1 3 a #> 3 3 1 c ``` --- # Sélection Dans un `data.frame` Deux approches pour sélectionner les colonnes d'un `data.frame`. ```r df <- data.frame(x = 1:3, y = 3:1, z = letters[1:3]) df[c("x", "z")] # approche liste ``` ``` #> x z #> 1 1 a #> 2 2 b #> 3 3 c ``` ```r df[, c("x", "z")] # approche matrice ``` ``` #> x z #> 1 1 a #> 2 2 b #> 3 3 c ``` --- # Sélection Dans un `data.frame` Attention, ces deux approches ne sont pas tout à fait équivalentes. ```r str(df["x"]) ``` ``` #> 'data.frame': 3 obs. of 1 variable: #> $ x: int 1 2 3 ``` ```r str(df[, "x"]) ``` ``` #> int [1:3] 1 2 3 ``` ```r str(df[, "x", drop = FALSE]) ``` ``` #> 'data.frame': 3 obs. of 1 variable: #> $ x: int 1 2 3 ``` --- # Exercices 1. Corriger les erreurs dans les codes suivants. ```r mtcars[mtcars$cyl = 4, ] mtcars[-1:4, ] mtcars[mtcars$cyl <= 5] mtcars[mtcars$cyl == 4 | 6, ] ``` 2. Pourquoi le code suivant renvoi cinq valeurs manquantes ? Et avec `x[NA_real_]` ? ```r x <- 1:5 x[NA] ``` ``` #> [1] NA NA NA NA NA ``` 3. Pourquoi `mtcars[1:20]` produit une erreur alors que `mtcars[1:20, ]` fonctionne ? Quelle est la différence ? 4. Que fait `df[is.na(df)] <- 0` ? Sur quel principe repose cette commande ? --- # Les Opérateurs `[[` et `$` `[[` renvoi toujours un élément plus petit. ```r x <- list(1:3, "a", 4:6) x[1] ``` ``` #> [[1]] #> [1] 1 2 3 ``` ```r x[[1]] ``` ``` #> [1] 1 2 3 ``` --- # Les Opérateurs `[[` et `$` `$` fonctionne d'une façon proche de celle de `[[`. ```r mitcars$cyl mitcars[["cyl"]] ``` --- # Les Opérateurs `[[` et `$` Le `$` n'est pas utilisable lorsque le nom de la colonne ou de l'élément est stockée dans une variable. ```r var <- "cyl" mtcars$var ``` ``` #> NULL ``` ```r mtcars[[var]] ``` ``` #> [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4 ``` --- # Les Opérateurs `[[` et `$` L'opérateur `$` permet également une correspondance partiel des noms, contrairement à `[[` (ou `[`). ```r x <- list(abc = 1) x$a ``` ``` #> [1] 1 ``` ```r x[["a"]] ``` ``` #> NULL ``` --- # Les Opérateurs `slot()` et `@` Les opérateurs `slot()` et `@` sont des opérateurs spécifiques des objets de classe S4, ou `slot()` correspond à `[[` et `@` à `$`. --- # Exercices 1. Extraire la troisième valeur de la variable `cyl` du jeu de données `mtcars`. 2. À partir de la régression linéaire `mod <- lm(mpg ~ wt, data = mtcars)`, extraire le nombre de degré de liberté. Puis extraire, le R carré du modèle (`summary(mod)`). --- # Sélection et Affectation Les opérateurs `[`, `[[` et `$` permettent également les affectations ou modifications. ```r x <- 1:5 x[c(1, 2)] <- c(101, 102) x ``` ``` #> [1] 101 102 3 4 5 ``` **Attention au recyclage des valeurs !** --- # Sélection et Affectation Approche identique pour les listes. ```r x <- list(a = 1, b = 2) x[["b"]] <- NULL x ``` ``` #> $a #> [1] 1 ``` ```r y <- list(a = 1, b = 2) y["b"] <- list(NULL) y ``` ``` #> $a #> [1] 1 #> #> $b #> NULL ``` ```r str(y) ``` ``` #> List of 2 #> $ a: num 1 #> $ b: NULL ``` --- # Sélection et Affectation Le cas de la sélection par "rien", c'est-à-dire, `df[]`, permet dans le cas d'une affectation de préservé la structure d'origine. ```r mtcars[] <- lapply(mtcars, as.integer) is.data.frame(mtcars) ``` ``` #> [1] FALSE ``` ```r mtcars <- lapply(mtcars, as.integer) is.data.frame(mtcars) ``` ``` #> [1] FALSE ``` --- # Exercices 1. Ajouter une colonne `cyl_fct` à `mtcars` comme une copie de la colonne `cyl`. Quel est le type de la nouvelle colonne ? Modifier le type de cette colonne dans un type plus approprié pour une analyse de comparaison de groupes défini par `cyl_fct`. 2. Reprendre les fonctions vu au préalable et identifier la structure, le type, la classe et les attributs des objets générés par ces fonctions, *p.ex.*, `stats::lm()`, `stats::aov()`, `t.test()`, `ggplot2::ggplot()`, etc. 3. Manipuler les fonctions `str()`, `typeof()`, `dput()`, `attributes()`, `attr()`, `dimnames()`, `dim()`, `rownames()`, `colnames()` et `names()` sur les jeux de données de `datasets` (`ls(name = "package:datasets")`). 4. Créer une liste, un vecteur, un `data.frame` à l'aide de la fonction `structure()`. --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Les Fonctions --- # Les Fonctions Une fonction se décompose en trois éléments : * Les arguments (`arguments`). * Le corps (`body`). * L'environnement (`environment`). --- # Les Fonctions ```r f <- function(x, y) { # Commentaire return(x + y) } ``` ```r f <- function(x, y) { # Commentaire x + y } ``` --- # Les Fonctions ```r formals(f) ``` ``` #> $x #> #> #> $y ``` ```r body(f) ``` ``` #> { #> x + y #> } ``` ```r environment(f) ``` ``` #> <environment: R_GlobalEnv> ``` --- # Les Fonctions Les fonctions sont des objets au même titre que les vecteurs. ```r attributes(f) ``` ``` #> $srcref #> function(x, y) { #> # Commentaire #> x + y #> } ``` --- # Les Fonctions * Fonction "classique", affectée d'un nom. ```r f <- function(x, y) { # Commentaire x + y } f(1, 2) ``` ``` #> [1] 3 ``` * Fonction anonyme. ```r (function(x, y) x + y)(1, 2) ``` ``` #> [1] 3 ``` --- # Les Fonctions Composées ```r square <- function(x) x^2 deviation <- function(x) x - mean(x) x <- runif(100) ``` --- # Les Fonctions Composées: Imbrication ```r sqrt(mean(square(deviation(x)))) ``` ``` #> [1] 0.3018447 ``` --- # Les Fonctions Composées: Séquentiel ```r out <- deviation(x) out <- square(out) out <- mean(out) out <- sqrt(out) out ``` ``` #> [1] 0.3018447 ``` --- # Les Fonctions Composées: "Pipe" `%>%` (`magrittr`) ```r library(magrittr) x %>% deviation() %>% square() %>% mean() %>% sqrt() ``` ``` #> [1] 0.3018447 ``` --- # Exercices 1. `match.fun()` permet de trouver une fonction avec son nom. À partir d'une fonction, est-il possible de trouver son nom ? 2. Quelles fonctions permettraient d'identifier si un objet est une fonction et s'il s'agit d'une primitive ? Par exemple, `+`, `sum`, `lm` et `t.test`. 3. Quelles sont les composantes d'une fonction ? `str`, `attributes`, `typeof`, `class`, etc. 4. Est-il possible de donner des attributs (*c.-à-d.*, avec `attr`) à une fonction ? --- class: part-slide # Fondamentaux "<i class="fab fa-r-project"></i> base"<br>Les Structures de Contrôle --- # Les Structures de Contrôle : `if ... else ...` La structure de contrôle "si sinon" s'écrit sous les formessuivantes : * `if (condition) action_si_vraie`, lorsque l'on ne souhaite rien faire si la condition est fausse. * `if (condition) action_si_vraie else action_si_fausse`, lorsque l'on souhaite définir une action que la condition soit vraie ou fausse. --- # Les Structures de Contrôle : `if ... else ...` Les structures `if ... else ...` peuvent être imbriquées : ```r if (x > 75) { "]75, Inf[" } else if (x > 50) { "]50, 75]" } else if (x > 25) { "]25, 50]" } else { "]-Inf, 25]" } ``` --- # Les Structures de Contrôle : `if ... else ...` `if ... else ...` renvoie un résultat comme n'importe quelle fonction. Ce résultat peut donc être affecté à une variable via l'opérateur `<-` (ou `=`)*. ```r resultat1 <- if (TRUE) "vrai" else "faux" resultat1 ``` ``` #> [1] "vrai" ``` ```r (resultat2 <- if (FALSE) "vrai" else "faux") ``` ``` #> [1] "faux" ``` ```r resultat2 ``` ``` #> [1] "faux" ``` .footnote[ * Pour des questions de clarté et lisibilité du code, l'affectation globale d'un `if ... else ...` est recommandé lorsque l'expression tient sur une seule ligne. ] --- # Les Structures de Contrôle : `if ... else ...` Avec ou sans `else`, un résultat est renvoyé : .pull-left[ * "visible" ```r if (FALSE) "vrai" else {} ``` ``` #> NULL ``` ```r (x1 <- if (FALSE) "vrai" else {}) ``` ``` #> NULL ``` ```r x1 ``` ``` #> NULL ``` ] .pull-right[ * "invisible" ```r if (FALSE) "vrai" ``` ```r (x2 <- if (FALSE) "vrai") ``` ``` #> NULL ``` ```r x2 ``` ``` #> NULL ``` ] --- # Les Structures de Contrôle : `if ... else ...` Une condition doit être un booléen (c'est-à-dire, `TRUE` ou `FALSE`) de longueur 1. ```r if ("FALSE") "vrai" if (NA) "vrai" ``` ``` #> Error in if (NA) "vrai": missing value where TRUE/FALSE needed ``` ```r if (logical()) "vrai" ``` ``` #> Error in if (logical()) "vrai": argument is of length zero ``` ```r if (1:5) "vrai" ``` ``` #> Warning in if (1:5) "vrai": the condition has length > 1 and only the first element will be used ``` ``` #> [1] "vrai" ``` --- # Les Structures de Contrôle : `if ... else ...` <i class="fab fa-r-project"></i> autorise cependant l'usage d'un vecteur de booléen d'une longueur supérieure à 1. ```r if (c(FALSE, TRUE)) "vrai" ``` ``` #> Warning in if (c(FALSE, TRUE)) "vrai": the condition has length > 1 and only the first element will be used ``` ```r if (c(TRUE, FALSE)) "vrai" ``` ``` #> Warning in if (c(TRUE, FALSE)) "vrai": the condition has length > 1 and only the first element will be used ``` ``` #> [1] "vrai" ``` --- # Les Structures de Contrôle : `if ... else ...` <i class="fab fa-r-project"></i> est un langage vectorielle, ainsi il existe `ifelse`. ```r ifelse(c(FALSE, TRUE), "vrai", "faux") ``` ``` #> [1] "faux" "vrai" ``` ```r ifelse(c(TRUE, FALSE), "vrai", "faux") ``` ``` #> [1] "vrai" "faux" ``` -- ```r ifelse(1:10 %% 2 == 0, "pair", "impair") ``` ``` #> [1] "impair" "pair" "impair" "pair" "impair" "pair" "impair" "pair" "impair" "pair" ``` ```r ifelse(1:10 %% 2 == 0, "pair", NA_character_) ``` ``` #> [1] NA "pair" NA "pair" NA "pair" NA "pair" NA "pair" ``` --- # Les Structures de Contrôle : `if ... else ...` <i class="fab fa-r-project"></i> propage les `NA` dans la sortie du `ifelse`. ```r x <- c(NA, 1:10, NA) ifelse(x %% 2 == 0, "pair", "impair") ``` ``` #> [1] NA "impair" "pair" "impair" "pair" "impair" "pair" "impair" "pair" "impair" "pair" #> [12] NA ``` --- # Les Structures de Contrôle : `switch` Le `switch` est un cas particulier de `if ... else ...`. .pull-left[ ```r set_option <- function(x) { if (x == "a") { "option 1" } else if (x == "b") { "option 2" } else if (x == "c") { "option 3" } else { stop("Option `x` non valide !") } } ``` ] -- .pull-right[ ```r set_option <- function(x) { switch(x, a = "Option 1", b = "Option 2", c = "Option 3", stop("Option `x` non valide !") ) } ``` ] La dernière instruction (sans nom) devrait contenir une erreur (c'est-à-dire, `stop("message")`). ```r (switch("c", a = 1, b = 2, stop("Erreur!"))) ``` ``` #> Error in eval(expr, envir, enclos): Erreur! ``` ```r (switch("c", a = 1, b = 2)) ``` ``` #> NULL ``` --- # Exercices 1. Quel type de vecteurs produisent les instructions suivantes ? Quelle est la règle (`?ifelse`) ? ```r ifelse(TRUE, 1, "no") ifelse(FALSE, 1, "no") ifelse(NA, 1, "no") ``` 2. Pour quelle raison les instructions suivantes fonctionnent ? ```r x <- 1:10 if (length(x)) "Non vide" else "Vide" x <- numeric() if (length(x)) "Non vide" else "Vide" ``` --- # Les Structures de Contrôle : `for (...) ...` * Les itérations à partir d'un vecteur de valeurs peut se faire via une boucle `for`. ```r for (element in vecteur) action ``` -- * L'action `action` est réalisée une fois par élément et donc autant de fois que la longeur de `vecteur`. ```r for (i in 1:3) { print(i) } ``` ``` #> [1] 1 #> [1] 2 #> [1] 3 ``` -- * La valeur de l'indice `i` est stockée dans l'environnement courant. ```r i <- "mon indice" for (i in 1:3) {} i ``` ``` #> [1] 3 ``` --- # Les Structures de Contrôle : `for (...) ...` Pour sortir prématurément d'une boucle `for` : * `next`, passe directement à l'élément suivant de la boucle et continu jusqu'à la fin. * `break`, provoque une sortie immédiate de la boucle. ```r for (i in 1:10) { if (i < 3) next print(i) if (i > 5) break } ``` ``` #> [1] 3 #> [1] 4 #> [1] 5 #> [1] 6 ``` --- # Les Structures de Contrôle : `for` oui, mais attention ! .pull-left[ * Initiliaser l'objet et remplir celui-ci, plutôt qu'aggréger. ```r x <- 1:10 resultats <- vector("numeric", length(x)) for (i in 1:length(x)) { resultats[[i]] <- sum(x[1:i]) } resultats ``` ``` #> [1] 1 3 6 10 15 21 28 36 45 55 ``` * Préférer `seq_along(x)` plutôt que `1:length(x)`. ```r x <- NULL 1:length(x) ``` ``` #> [1] 1 0 ``` ```r seq_along(x) ``` ``` #> integer(0) ``` ] .pull-right[ * Utiliser les fonctions vectorielles quand elles existent. ```r x <- 1:10 cumsum(x) ``` ``` #> [1] 1 3 6 10 15 21 28 36 45 55 ``` <img src="data:image/png;base64,#D:/Profils/mcanouil/PROJECTS/mc-radvanced/docs/index_files/figure-html/unnamed-chunk-145-1.svg" style="display: block; margin: auto;" /> ] --- # Exercices 1. Pourquoi le code suivant fonctionne sans erreurs ou avertissement ? ```r x <- numeric() out <- vector("list", length(x)) for (i in 1:length(x)) { out[i] <- x[i] ^ 2 } out ``` 2. Que se passe-t-il à chaque étape de la boucle `for` ? ```r xs <- c(1, 2, 3) for (x in xs) { xs <- c(xs, x * 2) } xs ``` --- class: part-slide # <img src = "data:image/png;base64,#https://avatars1.githubusercontent.com/u/8896044" height = "150px" id = "picture" /> .center[ <a href = "https://mickael.canouil.fr" target = "_blank"><i class = "fas fa-home"></i> mickael.canouil.fr</a> .column[ <a href = "https://www.linkedin.com/in/mickael-canouil/" target = "_blank"><i class = "fab fa-linkedin"></i> mickael-canouil</a> ] .column[ <a href = "https://github.com/mcanouil/" target = "_blank"><i class = "fab fa-github"></i> mcanouil</a> ] .column[ <a href = "https://twitter.com/mickaelcanouil/" target = "_blank"><i class = "fab fa-twitter"></i> @mickaelcanouil</a> ] ]